/*

Copyright (C) 2000 - 2008 Christian Kreibich <christian@whoop.org>.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies of the Software and its documentation and acknowledgment shall be
given in the documentation and software packages that this Software was
used.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

*/
#ifndef __nd_protocol_h
#define __nd_protocol_h

#include <gtk/gtk.h>

#include <nd_packet.h>
#include <nd_protocol_plugin.h>


#define ND_PROTO_MAGICS 3


/* A protocol can live at a combination of the following
 * layers.
 */
typedef enum {
  ND_PROTO_LAYER_LINK  = (1 << 0),
  ND_PROTO_LAYER_NET   = (1 << 1),
  ND_PROTO_LAYER_TRANS = (1 << 2),
  ND_PROTO_LAYER_APP   = (1 << 3)
} ND_ProtocolLayer;

typedef void (*ND_ProtoFieldCB) (LND_Packet  *packet,
				 guchar      *header,
				 guchar      *data);

struct nd_protocol
{
  /* Create a widget that represents this protocol, for
   * a given trace.
   */
  GtkWidget   *(*create_gui)          (LND_Trace *trace,
				       LND_ProtoInfo *pinf);
  
  /* Set this protocol's gui to the given packet, for
   * the given nesting level.
   */
  void         (*set_gui)             (const LND_Packet *packet,
				       LND_ProtoInfo *pinf);


  /* The header fields that are always present. E.g. TCP
   * headers without options, or type, code + checksum in ICMP.
   * Varying stuff is handled via nd_gui_proto_table_*().
   */
  ND_ProtoField             *fields;

  /* The width of the header in the GUI, in bits. You need to fill
   * this in during the init function of your protocol plugin.
   */
  int                        header_width;

  /* The size of the protocol header, in bits. Calculated automatically
   * during plugin initialization when the plugin uses a header field
   * table, otherwise you must set this value in your plugin's
   * init() callback.
   */
  int                        header_size;

  /* The protocol's own menu that gets hooked into the protocols
   * menu in the main window, as a submenu. The protocol may or
   * may not set this up in its init_proto implementation.
   */
  ND_GtkMenu                *menu;

  /* The menu item whose child is the above menu. This menu item
   * can be enabled/disabled to block the entire above menu when
   * the protocol currently isn't appropriate. See nd_packet.c:
   * nd_packet_set_gui().
   */
  GtkWidget                 *proto_menu_item;

  /* The plugin that takes care of the GUI aspect of the protocol */
  ND_ProtoPlugin            *plugin;
};


/* A header field can be of two types -- value field which means
 * it's a pushbutton with a normal label, or a flag field which
 * means it's a togglebutton, like for TCP SYN/ACK/.. or IP's
 * DF/MF.
 */
typedef enum
{
  ND_VAL_FIELD,
  ND_FLG_FIELD

} ND_ProtoFieldType;


/* A header field can be in two states -- normal and erroneous,
 * like a wrong checksum:
 */
typedef enum
{
  ND_FIELD_STATE_NORMAL,
  ND_FIELD_STATE_UNKN,
  ND_FIELD_STATE_ERROR

} ND_ProtoFieldState;


/* This structure represents a button in the GUI table
 * of a protocol.
 */
struct nd_protocol_field
{
  /* The type of the button -- normal, toggle, etc. */
  ND_ProtoFieldType     type;

  /* A label for the button, including necessary
   * printf() format specifiers.
   */
  char                 *label;

  /* A tooltip message to show when the user rests
   * the mouse pointer over the button.
   */
  char                 *tooltip;

  /* How many bits does this field consume? */
  int                   bits;

  /* The callback to call when the user clicks the button. */
  ND_ProtoFieldCB       callback;
};



ND_Protocol      *nd_proto_new(LND_Protocol *proto);

void              nd_proto_free(LND_Protocol *proto);

ND_Protocol      *nd_proto_get(const LND_Protocol *proto);

/*
ND_ProtoField    *nd_proto_field_duplicate(ND_ProtoField *field);
void              nd_proto_field_free(ND_ProtoField *field);
*/

/* Helper function for protocol plugin gui setting functions,
 * see e.g. protocols/ip/nd_ip_set_gui_XXX().
 */
void              nd_proto_field_set(const LND_ProtoInfo *pinf,
				     ND_ProtoField *field, void *data);

void              nd_proto_field_set_for_menu(const LND_ProtoInfo *pinf,
					      ND_ProtoField *field,
					      void *data,
					      ND_MenuData *menu,
					      char *alt_form_str);

const char       *nd_proto_field_to_string(const ND_ProtoField *field);

/* Helper functions that return key strings for use
 * e.g. for nd_trace_get|set_data. The data is statically
 * allocated, not thread safe (not that we're using threads
 * anywhere ...) and must be strdupped when you want to
 * keep the strings around.
 */
char             *nd_proto_get_opt_key(LND_Protocol *proto);



/* A couple of default header field callbacks for common
 * sizes. These use the data pointer directly and do NOT
 * iterate over all selected packets  etc.
 */

void   nd_proto_4bit_hi_cb(LND_Packet   *packet,
			   guchar       *header,
			   guchar       *data);

void   nd_proto_4bit_lo_cb(LND_Packet   *packet,
			   guchar       *header,
			   guchar       *data);

void   nd_proto_8bit_cb(LND_Packet   *packet,
			guchar       *header,
			guchar       *data);

void   nd_proto_16bit_cb(LND_Packet  *packet,
			 guchar      *header,
			 guchar      *data);

void   nd_proto_24bit_cb(LND_Packet  *packet,
			 guchar      *header,
			 guchar      *data);

void   nd_proto_32bit_cb(LND_Packet  *packet,
			 guchar      *header,
			 guchar      *data);


typedef enum {
  ND_PROT_CB_4LO,
  ND_PROT_CB_4HI,
  ND_PROT_CB_8,
  ND_PROT_CB_16,
  ND_PROT_CB_32
} ND_ProtoCallbackMode;


typedef struct nd_proto_callback_data
{
  LND_Protocol         *proto;
  guchar               *data;
  int                   nesting;
  guint                 offset;

  ND_ProtoCallbackMode  mode;

  gboolean              update_packet;

} ND_ProtoCallbackData;

/**
 * nd_proto_cb_data_new - creates callback data
 * @proto: protocol to use in callback
 * @data: data pointer to protocol header
 * @offset: offset of the affected field in bytes from start
 * of header
 * @update_packet: whether to call nd_packet_update() for
 * each modified packet.
 *
 * This function creates a helper data structure that
 * gets passed to the iterating callbacks
 * (nd_proto_iterate_8bit_cb() and friends).
 *
 * Returns: new callback data structure, or %NULL if allocation
 * failed.
 */
ND_ProtoCallbackData * nd_proto_cb_data_new(LND_Protocol *proto,
					    guchar *data,
					    guint offset,
					    gboolean update_packet);

void   nd_proto_cb_data_free(ND_ProtoCallbackData *cb_data);

void   nd_proto_iterate_4bit_hi_cb(LND_Packet *packet,
				   void       *user_data,
				   guint       value);

void   nd_proto_iterate_4bit_lo_cb(LND_Packet *packet,
				   void       *user_data,
				   guint       value);

void   nd_proto_iterate_8bit_cb(LND_Packet *packet,
				void       *user_data,
				guint       value);

void   nd_proto_iterate_16bit_cb(LND_Packet *packet,
				 void       *user_data,
				 guint       value);

void   nd_proto_iterate_32bit_cb(LND_Packet *packet,
				 void       *user_data,
				 guint       value);

/* Use the following casting macro to avoid problems when
 * casting stuff to void * when passing the DATA parameter
 * in the above calls:
 */
#define DATA_TO_PTR(data) (GINT_TO_POINTER((gint) (data)))

#endif
